package com.ones.kit.excel.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.idev.excel.ExcelWriter;
import cn.idev.excel.FastExcel;
import cn.idev.excel.write.metadata.WriteSheet;
import cn.idev.excel.write.metadata.fill.FillConfig;
import com.ones.kit.excel.exception.OnesExcelCodes;
import com.ones.kit.excel.exception.OnesExcelException;
import com.ones.kit.excel.handler.ExcelAnalysisEventListener;
import jakarta.servlet.http.HttpServletResponse;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.List;

/**
 * excel 工具类
 *
 * @author Clark
 * @version 2025-02-19
 */
@Slf4j
@UtilityClass
public class ExcelUtils {
    // 模板根路径
    private static final String PATH_ROOT = "excel/";
    // 模板后缀
    private static final String FILE_SUFFIX = ".xlsx";

    /**
     * excel模板填充下载传入参数
     */
    @Builder
    @Getter
    @Setter
    @ToString
    public static class ExportParam {
        /**
         * 模板名称：classpath:excel/之后全路径(不包含文件后缀.xlsx)
         */
        private String templateName;
        /**
         * 输出文件名(不包含文件后缀.xlsx)、默认值为当前时间
         */
        private String outFileName;
        /**
         * 表单项填充数据对象
         */
        private Object obj;
        /**
         * 列表项填充数据集合
         */
        private List list;
    }

    /**
     * 根据excel模板导出数据
     *
     * @param param
     */
    public void export(ExportParam param) {
        if (ObjectUtil.isNull(param) || StrUtil.isEmpty(param.getTemplateName())) {
            // excel导出请求参数不正确
            throw new OnesExcelException(OnesExcelCodes.excel_export_202);
        }
        try {
            HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
            // 获取模板路径
            String fullPath = getFullPath(param.getTemplateName());
            Resource resource = new ClassPathResource(fullPath);
            InputStream inputStream = resource.getInputStream();

            // 获取输出文件名
            String fileName = param.getOutFileName();
            if (StrUtil.isEmpty(fileName)) {
                fileName = DateUtil.format(DateUtil.date(), DatePattern.PURE_DATETIME_FORMAT);
            }

            String outFileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + outFileName + FILE_SUFFIX);

            try (ExcelWriter writer = FastExcel.write(response.getOutputStream()).withTemplate(inputStream).build()) {
                FillConfig config = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
                WriteSheet writeSheet = FastExcel.writerSheet(0).build();
                // 判断集合
                if (CollUtil.isNotEmpty(param.getList())) {
                    // 国际化赋值
//                    I18nUtils.copyValues(param.getList());
                    writer.fill(param.getList(), config, writeSheet);
                }
                // 判断对象
                if (ObjectUtil.isNotNull(param.getObj())) {
                    // 国际化赋值
//                    I18nUtils.copyValues(param.getObj());
                    writer.fill(param.getObj(), writeSheet);
                }
            }
        } catch (IOException e) {
            log.error("----------excel导出失败----------");
            e.printStackTrace();
            throw new OnesExcelException(OnesExcelCodes.excel_export_201);
        }
    }

    /**
     * 获取模板全路径
     *
     * @param templateName
     * @return
     */
    private String getFullPath(String templateName) {
//        String language = I18nUtils.getLanguage();
        String fullPath = PATH_ROOT + templateName;
//        // 根据语言获取模板
//        if (!DpnCoreConsts.ReqHeader.LANGUAGE_ZH.equals(language)) {
//            fullPath = fullPath + "-" + language;
//        }
        log.debug("----------excel模板全路径:{}", fullPath);
        return fullPath + FILE_SUFFIX;
    }

    /**
     * 导入excel数据
     *
     * @param inputStream
     * @param clazz
     * @return
     */
    public <T> List read(InputStream inputStream, Class<T> clazz) {
        ExcelAnalysisEventListener listener = new ExcelAnalysisEventListener();
        FastExcel.read(inputStream, clazz, listener)
                .ignoreEmptyRow(Boolean.TRUE) // 忽略空行
                .headRowNumber(1) // 表头行数
                .sheet().doRead();
        List<T> list = listener.getList();
        return list;
    }

    /**
     * 根据模板生成excel
     * @param param
     */
    public void write4Template(ExportParam param) {
        if (ObjectUtil.isNull(param) || StrUtil.isEmpty(param.getTemplateName())) {
            // excel导出请求参数不正确
            throw new OnesExcelException(OnesExcelCodes.excel_export_202);
        }

        File file = new File(param.getTemplateName() + FILE_SUFFIX);
        File outFile = new File(param.getOutFileName() + FILE_SUFFIX);

        try (ExcelWriter writer = FastExcel.write(file).withTemplate(outFile).build()) {
            FillConfig config = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
            WriteSheet writeSheet = FastExcel.writerSheet(0).build();
            // 判断集合
            if (CollUtil.isNotEmpty(param.getList())) {
                // 国际化赋值
//                    I18nUtils.copyValues(param.getList());
                writer.fill(param.getList(), config, writeSheet);
            }
            // 判断对象
            if (ObjectUtil.isNotNull(param.getObj())) {
                // 国际化赋值
//                    I18nUtils.copyValues(param.getObj());
                writer.fill(param.getObj(), writeSheet);
            }
        }
    }
}